// src/composables/useRemotePagedSelect.ts
import { ref, onMounted } from "vue";

export type Fetcher<T> = (params: {
  page: number;
  size: number;
  keyword: string;
}) => Promise<{ list: T[]; total?: number }>;

export function useRemotePagedSelect<T extends { id: string | number }>(opts: {
  pageSize?: number;
  autoLoad?: boolean;
  debounceMs?: number;
  fetcher: Fetcher<T>;
}) {
  const pageSize = opts.pageSize ?? 20;
  const autoLoad = opts.autoLoad ?? true;
  const debounceMs = opts.debounceMs ?? 300;

  // state
  const list = ref<T[]>([]);
  const keyword = ref<string>("");
  const loading = ref<boolean>(false);
  const hasMore = ref<boolean>(true);
  const page = ref<number>(1);
  const total = ref<number | undefined>(undefined);
  const error = ref<string | null>(null);

  // 本地去重索引（非响应式）
  const map = new Map<string | number, T>();

  // 请求序号，确保只采纳最后一次请求
  let reqSeq = 0;

  // 将要刷新标记（软重置）：不立即清空列表，等成功后替换
  let softReset = false;

  function hardClear() {
    list.value.length = 0;
    map.clear();
  }

  function applyReplace(items: T[]) {
    // 用新数据替换（避免“清空后失败导致空列表”的闪烁）
    hardClear();
    for (const it of items) {
      map.set(it.id, it);
      list.value.push(it);
    }
  }

  function applyAppend(items: T[]) {
    for (const it of items) {
      if (!map.has(it.id)) {
        map.set(it.id, it);
        list.value.push(it);
      } else {
        const merged = { ...(map.get(it.id) as T), ...it };
        map.set(it.id, merged);
        const idx = list.value.findIndex(x => x.id === it.id);
        if (idx !== -1) list.value[idx] = merged;
      }
    }
  }

  async function load(p = 1): Promise<void> {
    // 若是刷新第一页，先打软重置标记，但不清空
    if (p === 1) {
      softReset = true;
      page.value = 1;
      hasMore.value = true; // 先乐观为 true
      error.value = null;
    }

    // 生成本次请求的 id
    const id = ++reqSeq;
    loading.value = true;

    try {
      const { list: data, total: t } = await opts.fetcher({
        page: p,
        size: pageSize,
        keyword: keyword.value.trim()
      });

      // 只处理最后一次请求
      if (id !== reqSeq) return;

      const arr = Array.isArray(data) ? data : [];

      if (p === 1) {
        // 刷新模式：成功后再替换
        applyReplace(arr);
      } else {
        // 翻页模式：追加
        applyAppend(arr);
      }

      total.value = t;
      hasMore.value = arr.length >= pageSize;
      page.value = p;
      error.value = null;
    } catch (e: any) {
      // 只处理最后一次请求
      if (id !== reqSeq) return;

      error.value = e?.message ?? "加载失败";
      // 失败时：若是刷新第一页，不动现有列表（保留旧数据）
      // 也可以根据需要提示用户
    } finally {
      // 只处理最后一次请求
      if (id !== reqSeq) return;

      loading.value = false;
      softReset = false;
    }
  }

  async function loadMore(): Promise<void> {
    if (!hasMore.value || loading.value) return;
    await load(page.value + 1);
  }

  // 输入关键字（防抖 + 避免重复请求）
  let timer: ReturnType<typeof setTimeout> | null = null;
  function onKeywordInput(v: string): void {
    const nv = v ?? "";
    if (nv === keyword.value) return; // 相同输入不请求
    keyword.value = nv;
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => {
      void load(1);
    }, debounceMs);
  }

  // 下拉面板滚动触底
  function onDropdownScroll(e: Event): void {
    const el = e.target as HTMLElement;
    if (!el) return;
    const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 16;
    if (nearBottom) void loadMore();
  }

  // 显式重置（可选暴露）：清空所有状态
  function reset(): void {
    // 完全重置时，清空并重置指示器
    hardClear();
    page.value = 1;
    hasMore.value = true;
    total.value = undefined;
    error.value = null;
    keyword.value = "";
    reqSeq++; // 使任何进行中的请求结果被丢弃
    softReset = false;
  }

  onMounted(() => {
    if (autoLoad) void load(1);
  });

  return {
    // state
    list,
    keyword,
    loading,
    hasMore,
    total,
    error,
    // actions
    load,
    loadMore,
    onKeywordInput,
    onDropdownScroll,
    reset
  };
}
